// OrderEntryDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LightspeedTraderAPIDemo.h"
#include "OrderEntryDlg.h"
//#include "afxdialogex.h"


// OrderEntryDlg dialog

IMPLEMENT_DYNAMIC(OrderEntryDlg, CModelessDialog)

enum LOCAL_TIF_CONSTANTS {
	IOC,
	THIRTY_SECONDS,
	ONE_MINUTE,
	THREE_MINUTES,
	FOUR_MIN_FIFTY_SEC,
	ONE_HOUR,
	FOK,
	DAY
};

OrderEntryDlg::OrderEntryDlg(CWnd* pParent /*=NULL*/)
	: CModelessDialog(OrderEntryDlg::IDD, pParent)
	, summary(NULL)
	, account(NULL)
	, m_SymbolEdit(CEdit())
	, m_BidEdit(CEdit())
	, m_AskEdit(CEdit())
	, m_SharesEdit(CEdit())
	, m_PriceEdit(CEdit())
	, m_MarketEdit(CEdit())
	, m_VisibleSharesEdit(CEdit())
	, m_Price2Edit(CEdit())
	, m_Market2Edit(CEdit())
	, m_InfoEdit(CEdit())
	, m_OrderTypeCombo(CComboBox())
	, m_SideCombo(CComboBox())
	, m_TIFCombo(CComboBox())
	, m_HiddenCombo(CComboBox())
	, m_GoButton(CButton())
	, m_CancelButton(CButton())
	, HasEnteredSymbol(false)
	, m_lCorrelationId(0)
	, m_lReferenceId(0)
	, m_lReferenceId2(0)
	, m_Linked(false)
{

}

OrderEntryDlg::~OrderEntryDlg()
{
	if (account)
	{
		account->L_Detach(this);
		account = NULL;
	}

	if (summary)
	{
		summary->L_Detach(this);
		L_DestroySummary(summary);
	}
}

BOOL OrderEntryDlg::Create(CWnd *pParentWnd /*= CWnd::FromHandle(L_GetMainWnd())*/)
{
	return __super::Create(OrderEntryDlg::IDD, pParentWnd);
}

void OrderEntryDlg::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);

	DDX_Control(pDX, IDC_SYMBOLEDIT, m_SymbolEdit);
	DDX_Control(pDX, IDC_BIDEDIT, m_BidEdit);
	DDX_Control(pDX, IDC_ASKEDIT, m_AskEdit);
	DDX_Control(pDX, IDC_ORDERTYPECOMBO, m_OrderTypeCombo);
	DDX_Control(pDX, IDC_SIDECOMBO, m_SideCombo);
	DDX_Control(pDX, IDC_SHARESEDIT, m_SharesEdit);
	DDX_Control(pDX, IDC_PRICEEDIT, m_PriceEdit);
	DDX_Control(pDX, IDC_MARKETEDIT, m_MarketEdit);
	DDX_Control(pDX, IDC_TIFCOMBO, m_TIFCombo);
	DDX_Control(pDX, IDC_HIDDENCOMBO, m_HiddenCombo);
	DDX_Control(pDX, IDC_VISIBLESHARESEDIT,m_VisibleSharesEdit);
	DDX_Control(pDX, IDC_PRICE2EDIT, m_Price2Edit);
	DDX_Control(pDX, IDC_MARKET2EDIT, m_Market2Edit);
	DDX_Control(pDX, IDC_INFOEDIT, m_InfoEdit);
	DDX_Control(pDX, IDC_GO_BUTTON, m_GoButton);
	DDX_Control(pDX, IDC_CANCELORDER_BUTTON, m_CancelButton);
}

BOOL OrderEntryDlg::OnInitDialog()
{
	__super::OnInitDialog();

	m_OrderTypeCombo.InsertString(int(L_OrderType::MARKET), "Market");
	m_OrderTypeCombo.InsertString(int(L_OrderType::LIMIT), "Limit");
	m_OrderTypeCombo.InsertString(int(L_OrderType::STOP), "Stop");
	m_OrderTypeCombo.InsertString(int(L_OrderType::MOC), "Market on Close");
	m_OrderTypeCombo.InsertString(int(L_OrderType::LOC), "Limit on Close");
	m_OrderTypeCombo.InsertString(int(L_OrderType::CO), "Closing Offset");
	m_OrderTypeCombo.InsertString(int(L_OrderType::LOCI), "Limit on Close Imbalance");
	m_OrderTypeCombo.InsertString(int(L_OrderType::MOO), "Market on Open");
	m_OrderTypeCombo.InsertString(int(L_OrderType::LOO), "Limit on Open");
	m_OrderTypeCombo.InsertString(int(L_OrderType::LOOI), "Limit on Open Imbalance");
	m_OrderTypeCombo.InsertString(int(L_OrderType::ADDO), "Add Only");
	m_OrderTypeCombo.InsertString(int(L_OrderType::NROT), "Non-Routable");
	m_OrderTypeCombo.SetCurSel(int(L_OrderType::LIMIT));

	m_SideCombo.AddString(CString(L_Side::BUY));
	m_SideCombo.AddString(CString(L_Side::SELL));
	m_SideCombo.SetCurSel(0);

	m_SharesEdit.SetWindowText("100");

	m_MarketEdit.SetWindowText("NSDQ");

	m_TIFCombo.InsertString(IOC, "IOC");
	m_TIFCombo.InsertString(THIRTY_SECONDS, "30 Seconds");
	m_TIFCombo.InsertString(ONE_MINUTE, "1 Minute");
	m_TIFCombo.InsertString(THREE_MINUTES, "3 Minutes");
	m_TIFCombo.InsertString(FOUR_MIN_FIFTY_SEC, "4m 50s");
	m_TIFCombo.InsertString(ONE_HOUR, "1 Hour");
	m_TIFCombo.InsertString(FOK, "FOK");
	m_TIFCombo.InsertString(DAY, "Day");
	m_TIFCombo.SetCurSel(DAY);

	m_HiddenCombo.InsertString(0, "No");
	m_HiddenCombo.InsertString(1, "Yes");
	m_HiddenCombo.SetCurSel(0);

	m_VisibleSharesEdit.SetWindowText("0");

	m_Price2Edit.SetWindowText("0.0");

	account = L_GetAccount();
	account->L_Attach(this);

	L_AttachToAppNotifier(this);

	return TRUE;
}

void OrderEntryDlg::SummaryChanged()
{
	L1Update();

	if (summary)
	{
		CString ctrlText;

		ctrlText.Format("%.2f", summary->L_LastPrice());
		m_PriceEdit.SetWindowText(ctrlText);

		ctrlText = summary->L_Symbol();
		m_SymbolEdit.SetWindowText(ctrlText);

		HasEnteredSymbol = summary->L_IsValid() || summary->L_IsInit();

		m_GoButton.EnableWindow(HasEnteredSymbol);
	}
}

void OrderEntryDlg::L1Update()
{
	if (summary)
	{
		CString ctrlText;
		
		ctrlText.Format("%.2f", summary->L_Bid());
		m_BidEdit.SetWindowText(ctrlText);

		ctrlText.Format("%.2f", summary->L_Ask());
		m_AskEdit.SetWindowText(ctrlText);
	}
}

void OrderEntryDlg::DoGo()
{
	if (HasEnteredSymbol && summary)
	{
		//order values
		long type;
		char side;
		unsigned long shares;
		double price;
		CString market;
		long tif = 0;
		bool hidden;
		unsigned long visibleShares = 0;
		double price2 = 0.0;
		char *market2 = NULL;
		long correlationId = 0;
		char *info = NULL;

		CString ctrlText;

		//required parameters
		type = m_OrderTypeCombo.GetCurSel();

		m_SideCombo.GetLBText(m_SideCombo.GetCurSel(),ctrlText);
		side = ctrlText.GetBuffer()[0];

		m_SharesEdit.GetWindowText(ctrlText);
		shares = unsigned long(atol(ctrlText));

		m_PriceEdit.GetWindowText(ctrlText);
		price = atof(ctrlText.GetBuffer());

		m_MarketEdit.GetWindowText(market);
		market.Trim();

		switch (m_TIFCombo.GetCurSel())
		{
		case IOC: tif = L_TIF::IOC; break;
		
		//TIF = Number of second
		case THIRTY_SECONDS: tif = 30; break;
		case ONE_MINUTE: tif = 60; break;
		case THREE_MINUTES: tif = 180; break;
		case FOUR_MIN_FIFTY_SEC: tif = 290; break;
		case ONE_HOUR: tif = 3600; break;

		case FOK: tif = L_TIF::FOK; break;
		case DAY: tif = L_TIF::DAY; break;
		}
		
		//optional paramters
		hidden = bool(m_HiddenCombo.GetCurSel() != 0);

		m_VisibleSharesEdit.GetWindowText(ctrlText);
		visibleShares = unsigned long(atol(ctrlText));

		m_Price2Edit.GetWindowText(ctrlText);
		price2 = atof(ctrlText);

		m_Market2Edit.GetWindowText(ctrlText);
		ctrlText.Trim();
		if (! ctrlText.IsEmpty())
		{
			market2 = ctrlText.GetBuffer();
		}

		m_InfoEdit.GetWindowText(ctrlText);
		ctrlText.Trim();
		if (! ctrlText.IsEmpty())
		{
			info = ctrlText.GetBuffer();
		}

		account->L_SendOrder(summary,
							 type,
							 side,
							 shares,
							 price,
							 market.GetBuffer(),
							 tif,
							 hidden,
							 visibleShares,
							 price2,
							 market2,
							 &correlationId,
							 info);

		m_lCorrelationId = correlationId;
	}
}

void OrderEntryDlg::DoCancel()
{
	L_Order *order = NULL;
	if (account)
	{
		order = account->L_FindOrder(m_lReferenceId);
		if (order)
		{
			account->L_CancelOrder(order);
		}

		order = account->L_FindOrder(m_lReferenceId2);
		if (order)
		{
			account->L_CancelOrder(order);
		}
	}
}

//L_Oberver
void OrderEntryDlg::HandleMessage(L_Message const *pMsg)
{
	switch (pMsg->L_Type())
	{
	case L_MsgSymbolChanged::id:
		{
			if (m_Linked)
			{
				SetSymbol(pMsg->L_Symbol());
			}
		}
		break;
	case L_MsgL1::id:
	case L_MsgL1Change::id:
		SummaryChanged();
		break;
	case L_MsgL1Update::id:
		L1Update();
		break;
	case L_MsgOrderRequested::id:
		{
			L_MsgOrderRequested const *pMsgOrderRequested = static_cast<L_MsgOrderRequested const *>(pMsg);

			if (pMsgOrderRequested->L_CorrelationId() == m_lCorrelationId)
			{
				m_lReferenceId = pMsgOrderRequested->L_Order1ReferenceId();
				m_lReferenceId2 = pMsgOrderRequested->L_Order2ReferenceId();

				CString text;
				text.Format("MsgOrderRequested for CorrelationId %d. ReferenceId = %d, ReferenceId2 = %d"
					, m_lCorrelationId
					, m_lReferenceId
					, m_lReferenceId2);
				L_AddMessageToExtensionWnd(text.GetBuffer(),RGB(0,255,255));

				m_CancelButton.EnableWindow(TRUE);
			}
			else if (pMsgOrderRequested->L_SSMReplacedReferenceId() == m_lReferenceId
					|| pMsgOrderRequested->L_SSMReplacedReferenceId() == m_lReferenceId2)
			{
				m_lReferenceId = pMsgOrderRequested->L_Order1ReferenceId();
				m_lReferenceId2 = pMsgOrderRequested->L_Order2ReferenceId();

				CString text;
				text.Format("MsgOrderRequested replacing ReferenceId %d. ReferenceId = %d, ReferenceId2 = %d"
					, pMsgOrderRequested->L_SSMReplacedReferenceId()
					, m_lReferenceId
					, m_lReferenceId2);
				L_AddMessageToExtensionWnd(text.GetBuffer(), RGB(0,255,255));
			}
		}
		break;
	case L_MsgOrderChange::id:
		{
			L_MsgOrderChange const *pMsgOrderChange = static_cast<L_MsgOrderChange const *>(pMsg);

			if (pMsgOrderChange->L_ReferenceId() == m_lReferenceId
				|| pMsgOrderChange->L_ReferenceId() == m_lReferenceId2)
			{
				CString category, text;

				switch (pMsgOrderChange->L_Category())
				{
				case L_OrderChange::Other:
					category = "Other";
					break;
				case L_OrderChange::Create:
					category = "Create";
					break;
				case L_OrderChange::Receive:
					category = "Receive";
					break;
				case L_OrderChange::Exec:
					category = "Exec";
					break;
				case L_OrderChange::CancelCreate:
					category = "CancelCreate";
					break;
				case L_OrderChange::CancelRejection:
					category = "CancelRejection";
					break;
				case L_OrderChange::Cancel:
					category = "Cancel";
					break;
				case L_OrderChange::Kill:
					category = "Kill";
					break;
				case L_OrderChange::Rejection:
					category = "Rejection";
					break;
				}

				text.Format("MsgOrderChange Id %d. Category = %s", pMsgOrderChange->L_ReferenceId(), category.GetBuffer());
				L_AddMessageToExtensionWnd(text.GetBuffer(), RGB(0, 255, 255));
			}
		}
		break;
	}
}

BEGIN_MESSAGE_MAP(OrderEntryDlg, CModelessDialog)
	ON_EN_SETFOCUS(IDC_BIDEDIT, OnEnSetfocusBidEdit)
	ON_EN_SETFOCUS(IDC_ASKEDIT, OnEnSetfocusAskEdit)
	ON_BN_CLICKED(IDC_GO_BUTTON, OnBnClickedGoButton)
	ON_EN_CHANGE(IDC_SYMBOLEDIT, OnEnChangedSymbolEdit)
	ON_BN_CLICKED(IDC_CLOSE, CModelessDialog::OnClose)
	ON_BN_CLICKED(IDC_CANCELORDER_BUTTON, OnBnClickedCancelOrderButton)
	ON_COMMAND(ID_FILE_LINK ,OnFileLink)
END_MESSAGE_MAP()

// OrderEntryDlg message handlers

void OrderEntryDlg::OnOK()
{
	CString symbol;
	m_SymbolEdit.GetWindowText(symbol);
	
	if (symbol.GetLength() > 0 && (!summary || strcmp(summary->L_Symbol(), symbol.GetBuffer()) || !HasEnteredSymbol))
	{
		SetSymbol(symbol.GetBuffer());

		if (m_Linked)
		{
			L_SetFocusedSymbol(symbol.GetBuffer());
		}
	}
	else if (summary && !strcmp(summary->L_Symbol(), symbol.GetBuffer()))
	{
		DoGo();
	}
}

void OrderEntryDlg::SetSymbol(const char *symbol)
{
	if (summary)
	{
		summary->L_Detach(this);
		L_DestroySummary(summary);
	}

	summary = L_CreateSummary(symbol);
	summary->L_Attach(this);

	SummaryChanged();
}

void OrderEntryDlg::OnEnSetfocusBidEdit()
{
	CString bid = "0.0";
	m_BidEdit.GetWindowText(bid);
	m_PriceEdit.SetWindowText(bid);
}

void OrderEntryDlg::OnEnSetfocusAskEdit()
{
	CString ask = "0.0";
	m_AskEdit.GetWindowText(ask);
	m_PriceEdit.SetWindowText(ask);
}

void OrderEntryDlg::OnBnClickedGoButton()
{
	DoGo();
}

void OrderEntryDlg::OnEnChangedSymbolEdit()
{
	m_GoButton.EnableWindow(FALSE);
	HasEnteredSymbol = false;
}

void OrderEntryDlg::OnBnClickedCancelOrderButton()
{
	DoCancel();
}

void OrderEntryDlg::OnFileLink()
{
	m_Linked = !m_Linked;

	CMenu *menu = GetMenu();	
	menu->CheckMenuItem(ID_FILE_LINK, (m_Linked ? MF_CHECKED : MF_UNCHECKED) );
	
	if (m_Linked)
	{
		SetSymbol(::L_GetFocusedSymbol());
	}
}